home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 8 / Night Owl CD-ROM (NOPV8) (Night Owl Publisher) (1993).ISO / 034a / aecur101.arj / CONTRIB / CURSES / SRC / PMENUOBJ.C < prev    next >
C/C++ Source or Header  |  1990-03-08  |  7KB  |  368 lines

  1. /*------------------------------------------------------------
  2.  * 
  3.  *  pmenuobj.c
  4.  * 
  5.  *  Popup MENU OBJect
  6.  * 
  7.  *  copyright (c) 1988,89,90 J. Alan Eldridge
  8.  *
  9.  *----------------------------------------------------------*/
  10.  
  11. #include "curses.h"
  12.  
  13. extern WINDOW *newwin(), *subwin(), *savescr();
  14.  
  15. /* constructor function */
  16.  
  17. int
  18. pm_ctor(this, id, y, x, title, maxr, arr, norm, high)
  19. POPUP_MENU *this;
  20. int     id, y, x;
  21. char    *title;
  22. int     maxr;
  23. char    **arr;
  24. int     norm, high;
  25. {
  26.     int r, c, scroll;
  27.     
  28.     /* count items & determine window size */
  29.  
  30.     this->itemcnt = scrollmsize(title, maxr, arr, &r, &c, &scroll);
  31.     if (this->itemcnt == 0)
  32.         return ERR;
  33.     
  34.     /* set default origin if asked to */
  35.     
  36.     if (y < 0 || x < 0) {
  37.         getyx(curscr, y, x);
  38.         calcpopyx(r, c, y, x, x, &y, &x);
  39.     }
  40.     
  41.     /* try to allocate window including frame */
  42.  
  43.     if (!(this->box = newwin(r, c, y, x)))
  44.         return ERR;
  45.     
  46.     /* set attributes if necessary & possible */
  47.     
  48.     if (iscolor()) {
  49.         if (norm != -1)
  50.             setnorm(this->box, norm);
  51.         if (high != -1)
  52.             setstand(this->box, high);
  53.     wstandend(this->box);
  54.     }
  55.     
  56.     /* get a subwindow for the items */
  57.  
  58.     if (!(this->win = subwin(this->box, r - 2, c - 2, y + 1, x + 1))) {
  59.         delwin(this->box);
  60.         return ERR;
  61.     }
  62.  
  63.     /* save what's under the window */
  64.     
  65.     if (!(this->save = savescr(r, c, y, x))) {
  66.         delwin(this->win);
  67.         delwin(this->box);
  68.         return ERR;
  69.     }
  70.     
  71.     scrollok(this->win, 0);
  72.     wrapok(this->win, 0);
  73.     
  74.     box(this->box, 0, 0);
  75.     
  76.     if (title)
  77.         mvwaddstr(this->box, 0, 1, title);
  78.     
  79.     if (scroll) {
  80.         mvwaddch(this->box, 1, getmaxc(this->box), CH_UPARROW);
  81.         mvwaddch(this->box, getmaxr(this->box) - 1, 
  82.         getmaxc(this->box), CH_DNARROW);
  83.     }
  84.  
  85.     this->itemlist = arr;
  86.     this->curitem = this->topitem = 1;
  87.     this->id = id;
  88.  
  89.     return OK;
  90. }
  91.  
  92. /* destructor function : also restores screen */
  93.  
  94. void
  95. pm_dtor(this)
  96. POPUP_MENU *this;
  97. {
  98.     delwin(this->win);
  99.     delwin(this->box);
  100.     restscr(this->save);
  101.     delwin(this->save);
  102. }
  103.  
  104. /* 
  105.     calculate size needed by popup menu window 
  106.     and whether or not menu needs to scroll
  107.  
  108.     returns # of items in array
  109. */
  110.  
  111. int
  112. scrollmsize(title, maxr, arr, rp, cp, scrollp)
  113. char    *title;
  114. int     maxr;
  115. char    **arr;
  116. int     *rp, *cp, *scrollp;
  117. {
  118.     int icnt, ccnt, ilen;
  119.     
  120.     icnt = 0;
  121.     ccnt = title ? strlen(title) : 0;
  122.     
  123.     while (*arr) {
  124.         icnt++;
  125.         ilen = strlen(*arr);
  126.         if (ilen > ccnt)
  127.             ccnt = ilen;
  128.         arr++;
  129.     }
  130.     
  131.     if (maxr > 0 && maxr < icnt) {
  132.         *scrollp = 1;
  133.         *rp = maxr + 2;
  134.     } else {
  135.         *scrollp = 0;
  136.     *rp = icnt + 2;
  137.     }
  138.     
  139.     *cp = ccnt + 4;
  140.     
  141.     return icnt;
  142. }
  143.  
  144. int
  145. popmsize(title, arr, rp, cp)
  146. char    *title, **arr;
  147. int     *rp, *cp;
  148. {
  149.     int dummy;
  150.     
  151.     return scrollmsize(title, -1, arr, rp, cp, &dummy);
  152. }
  153.  
  154. /* draw popup menu with current item highlighted */
  155.  
  156. void
  157. pm_draw(this)
  158. POPUP_MENU *this;
  159. {
  160.     int r, rcnt, aidx, cidx;
  161.     
  162.     rcnt = getmaxr(this->win) + 1;
  163.     aidx = this->topitem - 1;
  164.     cidx = this->curitem - 1;
  165.  
  166.     for (r = 0; rcnt-- > 0; r++, aidx++) {
  167.         if (aidx == cidx)
  168.             wstandout(this->win);
  169.         mvwaddch(this->win, r, 0, ' ');
  170.         waddstr(this->win, this->itemlist[aidx]);
  171.         wclrtoeol(this->win);
  172.         if (aidx == cidx)
  173.             wstandend(this->win);
  174.     }
  175.  
  176.     touchwin(this->box);
  177.     wrefresh(this->box);
  178. }
  179.  
  180. /* change attributes of a row of a window */
  181.  
  182. static void
  183. overat(win, row, cnt)
  184. WINDOW  *win;
  185. int     row, cnt;
  186. {
  187.     wmove(win, row, 0);
  188.     while (cnt-- > 0)
  189.         waddch(win, winch(win));
  190. }
  191.  
  192. /* set scrolling style */
  193.  
  194. static int smooth = 1;
  195.  
  196. void
  197. pm_smooth(flag)
  198. int flag;
  199. {
  200.     smooth = flag;
  201. }
  202.  
  203. /* highlight next item, scrolling if necessary */
  204.  
  205. void
  206. pm_next(this, redraw_flag)
  207. POPUP_MENU *this;
  208. int     redraw_flag;
  209. {
  210.     int rcnt, ccnt, crow;
  211.     
  212.     if (this->curitem == this->itemcnt) {
  213.         /* beep(); */
  214.         return;
  215.     }
  216.  
  217.     getmaxrc(this->win, rcnt, ccnt);
  218.     rcnt++;
  219.     ccnt++;
  220.     this->curitem++;
  221.     
  222.     if (this->curitem < this->topitem + rcnt) {
  223.         crow = this->curitem - this->topitem;
  224.         overat(this->win, crow - 1, ccnt);
  225.         wstandout(this->win);
  226.         overat(this->win, crow, ccnt);
  227.         wstandend(this->win);
  228.         if (redraw_flag)
  229.             wrefresh(this->win);
  230.     } else {
  231.         /* must scroll up */
  232.         if (smooth) 
  233.             this->topitem++;
  234.         else {
  235.             this->topitem += rcnt - 1;
  236.             if (this->topitem + rcnt - 1 > this->itemcnt)
  237.                 this->topitem = this->itemcnt - rcnt + 1;
  238.         }
  239.         if (redraw_flag)
  240.             pm_draw(this);
  241.     }
  242. }
  243.  
  244. /* highlight previous item, scrolling if necessary */
  245.  
  246. void
  247. pm_prev(this, redraw_flag)
  248. POPUP_MENU *this;
  249. int     redraw_flag;
  250. {
  251.     int rcnt, ccnt, crow;
  252.     
  253.     if (this->curitem == 1) {
  254.         /*beep();*/
  255.         return;
  256.     }
  257.     
  258.     getmaxrc(this->win, rcnt, ccnt);
  259.     rcnt++;
  260.     ccnt++;
  261.     this->curitem--;
  262.     
  263.     if (this->curitem >= this->topitem) {
  264.         crow = this->curitem - this->topitem;
  265.         overat(this->win, crow + 1, ccnt);
  266.         wstandout(this->win);
  267.         overat(this->win, crow, ccnt);
  268.         wstandend(this->win);
  269.         if (redraw_flag)
  270.             wrefresh(this->win);
  271.     } else {
  272.         /* must scroll down */
  273.         if (smooth) 
  274.             this->topitem--;
  275.         else {
  276.             this->topitem -= rcnt - 1;
  277.             if (this->topitem < 1)
  278.                 this->topitem = 1;
  279.         }
  280.         if (redraw_flag)
  281.             pm_draw(this);
  282.     }
  283. }
  284.  
  285. /* user i/o function : returns 0 for abort otherwise choice (first = 1) */
  286.  
  287. int
  288. pm_choose(this)
  289. POPUP_MENU *this;
  290. {
  291.     int c;
  292.     
  293.     pm_draw(this);
  294.     
  295.     hidecursor();
  296.     while ((c = wgetch(this->win)) != K_ESC && c != K_NL)
  297.         switch (c) {
  298.         case K_SPACE:
  299.         case K_TAB:
  300.         case K_RIGHT:
  301.         case K_DOWN:
  302.             pm_next(this, 1);
  303.             break;
  304.         case K_BACK:
  305.         case K_LEFT:
  306.         case K_UP:
  307.             pm_prev(this, 1);
  308.             break;
  309.         default:
  310.             beep();
  311.             break;
  312.         }
  313.     showcursor();
  314.  
  315.     return c == K_ESC ? 0 : this->curitem;
  316. }
  317.  
  318. /* 
  319.     set the current item pointer 
  320.     
  321.     this is a pessimal implementation ...
  322.     (make it work, then make it fast - kernighan)
  323. */
  324.  
  325. int
  326. pm_select(this, item_num)
  327. POPUP_MENU *this;
  328. int     item_num;
  329. {
  330.     int cur_item = this->curitem;
  331.     int item_cnt = this->itemcnt;
  332.  
  333.     if (item_num > item_cnt || item_num < 1)
  334.         return ERR;
  335.         
  336.     /* 
  337.         notice that at most one of these
  338.         while loops will execute 
  339.     */
  340.     
  341.     while (cur_item > item_num) {
  342.         cur_item--;
  343.         pm_prev(this, 0);
  344.     }
  345.     while (cur_item++ < item_num)
  346.         pm_next(this, 0);
  347.                 
  348.     return OK;
  349. }
  350.  
  351. /* return the itemlist pointer */
  352.  
  353. char **
  354. pm_itemlist(this)
  355. POPUP_MENU *this;
  356. {
  357.     return this->itemlist;
  358. }
  359.  
  360. /* return the menu id */
  361.  
  362. int
  363. pm_id(this)
  364. POPUP_MENU *this;
  365. {
  366.     return this->id;
  367. }
  368.